/**
 * 版权所有 2009-2012
 * 山东新北洋信息技术股份有限公司
 * 保留所有权利。
 */
package com.jiashihui.schema_lgorithm.java.socket.service2;

import com.jiashihui.schema_lgorithm.config.ServerConfiguration;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * Server
 * 新北洋把枪程序集包服务核心启动类
 */
@Component
@Order(1)
public class Server implements ApplicationRunner {
    private static final Logger LOGGER = LoggerFactory.getLogger(Server.class);
    private static final int NUM_2 = 2;
    private static final int NUM_128 = 128;
    private static final int NUM_3000 = 3000;

    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private Channel serverChannel;

    @Autowired
    private ServerConfiguration config;

    /**
     * 启动
     * 服务
     * 入口
     *
     * @param arg0 application 参数
     */
    @Override
    public void run(ApplicationArguments arg0) throws Exception {
        try {
            start();
        } catch (Exception e) {
            LOGGER.error("service exception stop ", e);
            stop();
        }
    }

    /**
     * 服务
     * 启动
     * 方法
     */
    public void start() {
        LOGGER.debug("..................");
        // 看做一个死循环，程序永远保持运行
        // 完成线程的接收，将连接发送给worker
        // Runtime.availableProcessors() 获得可用的处理器个数
        bossGroup = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors() * NUM_2);
        // 完成连接的处理
        workerGroup = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors() * NUM_2);
        try {
            // 对于相关启动信息进行封装
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            // 注入两个group
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ServerChannelInitializer())
                    .option(ChannelOption.SO_BACKLOG, NUM_128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    .childOption(ChannelOption.SO_REUSEADDR, true)
                    .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, NUM_3000);
            // bind and start to accept incoming connections.
            // ChannelFuture的作用是用来保存Channel异步操作的结果
            // 绑定端口对端口进行监听,启动服务器
            ChannelFuture channelFuture = serverBootstrap.bind(config.getPort()).sync();
            serverChannel = channelFuture.channel();
            LOGGER.info("Server start port={} OK!", config.getPort());
        } catch (Exception e) {
            LOGGER.error("Server start error: {}", e);
            stop();
        }
    }

    /**
     * 服务
     * 停止
     */
    private void stop() {
        if (serverChannel != null) {
            serverChannel.close();
        }
        if (workerGroup != null) {
            workerGroup.shutdownGracefully();
        }
        if (bossGroup != null) {
            bossGroup.shutdownGracefully();
        }
        LOGGER.info("Server is shut down");
    }


}
